bitkeeper revision 1.1108.13.1 (41013a844lXqlHgR5n6-9AZ5s3WCsQ)
authortw275@labyrinth.cl.cam.ac.uk <tw275@labyrinth.cl.cam.ac.uk>
Fri, 23 Jul 2004 16:19:16 +0000 (16:19 +0000)
committertw275@labyrinth.cl.cam.ac.uk <tw275@labyrinth.cl.cam.ac.uk>
Fri, 23 Jul 2004 16:19:16 +0000 (16:19 +0000)
Added general support for actions
Slightly generalized and refactored code for modules / tabs

13 files changed:
.rootkeys
tools/python/xen/sv/DomInfo.py
tools/python/xen/sv/GenTabbed.py
tools/python/xen/sv/HTMLBase.py
tools/python/xen/sv/Main.py
tools/python/xen/sv/NodeInfo.py
tools/python/xen/sv/util.py
tools/python/xen/xend/XendClient.py
tools/sv/Makefile
tools/sv/images/reboot.png [new file with mode: 0755]
tools/sv/images/shutdown.png [new file with mode: 0755]
tools/sv/inc/script.js [new file with mode: 0755]
tools/sv/inc/style.css

index 424d963f29e69f85e98022f0385d2a21a9d52ac5..5ea44cb2742af5bda34e65e3e09596c5944b6331 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40fcefb38OTgsUKHBpwshLLIsiIaCA tools/sv/images/middle-no-highlight.jpg
 40fcefb32SPtrw36c4S6YGFlLvkKuw tools/sv/images/orb_01.jpg
 40fcefb3Ok5qkX3iM7ZEPVkRInrUpg tools/sv/images/orb_02.jpg
+41013a82ILk71xLqWFH5ZO5VmOIvBw tools/sv/images/reboot.png
 40fcefb3JnT5XeKTuVF4yUMGOtuNZg tools/sv/images/right-end-highlight.jpg
 40fcefb3-DuYOS7noo2W7b_0p7TOUg tools/sv/images/right-end-no-highlight.jpg
 40fcefb3qNbAZR5FYGPAZ9sFPVMTDA tools/sv/images/seperator-left-highlight.jpg
 40fcefb3dgsa24WLk_BJeYQHrDLuOg tools/sv/images/seperator-right-highlight.jpg
 40fcefb3FtiX4Pd2kT8wDlp8u8xRhQ tools/sv/images/seperator.jpg
+41013a82sUdUqBv8EoAUJii3gsZ-4g tools/sv/images/shutdown.png
 40fcefb3yMSrZvApO9ToIi-iQwnchA tools/sv/images/xen.png
+41013a83z27rKvWIxAfUBMVZ1eDCDg tools/sv/inc/script.js
 40fcefb3zGC9XNBkSwTEobCoq8YClA tools/sv/inc/style.css
 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile
 40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats
index 42abdee799e22eb35aef19de3245cc8003cd3f17..a718871fd55e7f17902529be6b1d58056350a12b 100755 (executable)
@@ -14,7 +14,7 @@ class DomInfo( GenTabbed ):
         def tabUrlWriter( tab ):
             return urlWriter( "mod=info&dom=%s%s" % ( self.dom, tab ) )
         
-        GenTabbed.__init__( self, tabUrlWriter, [ 'General', 'SXP', 'Devices' ], [ DomGenTab, DomSXPTab, NullTab ]  )
+        GenTabbed.__init__( self, "Domain Info", tabUrlWriter, [ 'General', 'SXP', 'Devices' ], [ DomGeneralTab, DomSXPTab, NullTab ]  )
 
     def write_BODY( self, request ):
         dom = request.args.get('dom')
@@ -27,6 +27,10 @@ class DomInfo( GenTabbed ):
         
         GenTabbed.write_BODY( self, request )
 
+class DomGeneralTab( CompositeTab ):
+    def __init__( self ):
+       CompositeTab.__init__( self, [ DomGenTab, DomActionTab ] )        
+        
 class DomGenTab( GeneralTab ):
 
     def __init__( self ):
@@ -41,7 +45,7 @@ class DomGenTab( GeneralTab ):
         titles[ 'Total CPU' ] = ( 'cpu_time', smallTimeFormatter )
         titles[ 'Up Time' ] = ( 'up_time', bigTimeFormatter )
     
-        GeneralTab.__init__( self, "General Domain Info", {}, titles )
+        GeneralTab.__init__( self, {}, titles )
         
     def write_BODY( self, request ):
     
@@ -79,4 +83,18 @@ class DomSXPTab( PreTab ):
         
         PreTab.write_BODY( self, request )
         
+class DomActionTab( ActionTab ):
+
+    def __init__( self ):
+        ActionTab.__init__( self, { "shutdown" : ( "Shutdown the Domain", "shutdown.png" ),
+               "reboot" : ( "Reboot the Domain", "reboot.png" ) } )    
+        
+    def op_shutdown( self, request ):
+       print ">DomShutDown"
+       #server.xend_node_shutdown()
+    
+    def op_reboot( self, request ):
+       print ">DomReboot"
+        #server.xend_node_reboot()
+        
 
index bfbe5b04cf65be57d32ba3f895ee73920ae33640..1d5bd2d22ac9498d9fc2fd8e727d054dd511809e 100755 (executable)
@@ -5,12 +5,13 @@ from xen.sv.TabView import TabView
 
 class GenTabbed( HTMLBase ):
 
-    def __init__( self, urlWriter, tabStrings, tabObjects ):
+    def __init__( self, title, urlWriter, tabStrings, tabObjects ):
         HTMLBase.__init__(self)
         self.tab = 0;
         self.tabStrings = tabStrings
         self.tabObjects = tabObjects
         self.urlWriter = urlWriter
+        self.title = title
 
     def write_BODY( self, request, urlWriter = None ):
         tab = request.args.get('tab')
@@ -23,19 +24,34 @@ class GenTabbed( HTMLBase ):
         request.write( "<table style='' width='100%' border='0' cellspacing='0' cellpadding='0'>" )
         request.write( "<tr><td>" )
         
+        request.write( "<p align='center'><u>%s</u></p>" % self.title )
+        
         TabView( self.tab, self.tabStrings, self.urlWriter ).write_BODY( request )
         
         request.write( "</td></tr><tr><td>" )
         
-        render_tab = self.tabObjects[ self.tab ]()
+        render_tab = self.tabObjects[ self.tab ]
                 
         if render_tab is None:
             request.write( "<p>Bad Tab</p>" )
             self.finish_BODY( request )
         else:
-            render_tab.write_BODY( request )
+            render_tab().write_BODY( request )
 
         request.write( "</td></tr></table>" )
+       
+    def perform( self, request ):
+        tab = request.args.get('tab')
+        
+        if tab is None or len( tab) != 1:
+            self.tab = 0
+        else:
+            self.tab = int( tab[0] )
+            
+        op_tab = self.tabObjects[ self.tab ]
+        
+        if op_tab:
+            op_tab().perform( request )
         
 class PreTab( HTMLBase ):
 
@@ -45,7 +61,7 @@ class PreTab( HTMLBase ):
     
     def write_BODY( self, request ):
         
-        request.write( "<div style='display: block; overflow: auto; border: 0px solid black; height: 400px; width: 540px; padding: 5px; z-index:0; align: center'><pre>" )
+        request.write( "<div style='display: block; overflow: auto; border: 0px solid black; width: 540px; padding: 5px; z-index:0; align: center'><pre>" )
         
         request.write( self.source )
         
@@ -53,16 +69,13 @@ class PreTab( HTMLBase ):
 
 class GeneralTab( HTMLBase ):
                         
-    def __init__( self, title, dict, titles ):
+    def __init__( self, dict, titles ):
         HTMLBase.__init__( self )
-        self.title = title
         self.dict = dict
         self.titles = titles
                         
     def write_BODY( self, request ): 
         
-        request.write( "<p><u>%s</u></p>" % self.title )
-        
         request.write( "<table width='100%' cellspacing='0' cellpadding='0' border='0'>" )
         
         def writeAttr( niceName, attr, formatter=None ):
@@ -90,4 +103,38 @@ class NullTab( HTMLBase ):
     def write_BODY( self, request ):
         request.write( "<p>%s</p>" % self.title )
 
+class ActionTab( HTMLBase ):
+
+    def __init__( self, actions ):
+        self.actions = actions
+        HTMLBase.__init__( self )
+        
+    def write_BODY( self, request ):
+        request.write("<p align='center'>")
+         
+        for ( command, ( text, image ) ) in self.actions.items():
+            request.write("<img src='images/%s' width='54' height='54' onclick='doOp( \"%s\" )' onmouseover='update( \"button_desc\", \"%s\" )' " % ( image, command, text ) )
+            request.write("onmouseout='update( \"button_desc\", \"&nbsp;\" )' style='button'>")
+            request.write("&nbsp;&nbsp;")
+    
+        request.write("<p align='center'><span id='button_desc'>&nbsp;</span></p>")   
+        request.write("</p>")        
+        
+class CompositeTab( HTMLBase ):
+
+    def __init__( self, tabs ):
+       HTMLBase.__init__( self )
+        self.tabs = tabs
+        
+    def write_BODY( self, request ):
+       for tab in self.tabs:
+            request.write( "<br/>" )
+            tab().write_BODY( request )
+            
+    def perform( self, request ):
+       for tab in self.tabs:
+            tab().perform( request )
+    
+    
+       
         
index 4479d7e4558c9305edaddc1459832bf6d9cfb76b..7c500e8a2b93101fe679d1191173743fd75bf393 100755 (executable)
@@ -7,6 +7,10 @@ class HTMLBase( Resource ):
     def __init__( self ):
         Resource.__init__(self)
 
+    def render_POST( self, request ):
+        self.perform( request )
+        self.render_GET( request ) 
+        
     def render_GET( self, request ):
         self.write_TOP( request )
         self.write_BODY( request )
@@ -19,7 +23,40 @@ class HTMLBase( Resource ):
         
     def write_TOP( self, request ):
         request.write( '<html><head><title>Xen</title><link rel="stylesheet" type="text/css" href="inc/style.css" />' )
+        request.write( '<script src="inc/script.js"></script>' )
         request.write( '</head><body>' )
 
     def write_BOTTOM( self, request ):
+        request.write('<form method="post" action="%s">' % request.uri)
+        request.write('<input type="hidden" name="op" value="">')
+        request.write('</form>')
         request.write( "</body></html>" )
+
+    def get_op_method(self, op):
+        """Get the method for an operation.
+        For operation 'foo' looks for 'op_foo'.
+
+        op     operation name
+        returns method or None
+        """
+        op_method_name = 'op_' + op
+        return getattr(self, op_method_name, None)
+        
+    def perform(self, req):
+        """General operation handler for posted operations.
+        For operation 'foo' looks for a method op_foo and calls
+        it with op_foo(req). Replies with code 500 if op_foo
+        is not found.
+
+        The method must return a list when req.use_sxp is true
+        and an HTML string otherwise (or list).
+        Methods may also return a Deferred (for incomplete processing).
+
+        req    request
+        """
+        op = req.args.get('op')
+        if not op is None and len(op) == 1:
+            op = op[0]
+            op_method = self.get_op_method(op)
+            if op_method:
+                op_method( req )   
index 6b9bbfae05dcd9b158555f6b9df21617bfc51261..50712c7710b082b33ece7fb872b4559cc720f963 100755 (executable)
@@ -1,14 +1,31 @@
 from xen.sv.HTMLBase import HTMLBase
-from xen.sv import DomList, NodeInfo, DomInfo
+from xen.sv.DomList  import DomList
+from xen.sv.NodeInfo import NodeInfo
+from xen.sv.DomInfo  import DomInfo
 
 class Main( HTMLBase ):
     
     isLeaf = True
 
-    def __init__( self ):
+    def __init__( self, urlWriter = None ):
+        self.modules = { "node": ( "Node details", NodeInfo ), 
+                         "list": ( "Domain summary", DomList ), 
+                         "info": ( "Domain info", DomInfo ) }
         HTMLBase.__init__(self)
         
     def render_POST( self, request ):
+    
+       #decide what module post'd the action
+
+        mod = request.args.get('mod')
+                
+        if not mod is None and len(mod) == 1:
+            modTup = self.modules[ mod[0] ]
+            #check module exists
+            if modTup:
+               (modName, module) = modTup
+               module( self.mainUrlWriter ).perform( request )     
+    
         return self.render_GET( request )
 
     def mainUrlWriter( self, s ):
@@ -25,10 +42,10 @@ class Main( HTMLBase ):
         request.write( "   <img src='images/xen.png' width='150' height='75' border='0'/></a></td></tr>" )
         request.write( "   <tr><td align='center' valign='top'>" )
         
-        request.write( "    <p class='small'><a href='Main.rpy?mod=node'>Node details</a></p>" )
-        request.write( "    <p class='small'><a href='Main.rpy?mod=list'>Domains summary</a></p>" )
+        for (modName, (modTitle, module)) in self.modules.items():
+            request.write( "    <p class='small'><a href='Main.rpy?mod=%s'>%s</a></p>" % (modName, modTitle))
     
-        DomList.DomList( self.mainUrlWriter ).write_BODY( request, True, False )
+        DomList( self.mainUrlWriter ).write_BODY( request, True, False )
 
         request.write( "   </td></tr>" )
         request.write( "  </table>" )
@@ -44,14 +61,13 @@ class Main( HTMLBase ):
         
         if mod is None or len(mod) != 1:
             request.write( '<p>Please select a module</p>' )
-        elif mod[0] == 'info':
-            DomInfo.DomInfo( self.mainUrlWriter ).write_BODY( request )
-        elif mod[0] == 'list':
-            DomList.DomList( self.mainUrlWriter ).write_BODY( request )
-        elif mod[0] == 'node':
-            NodeInfo.NodeInfo( self.mainUrlWriter ).write_BODY( request )
         else:
-            request.write( '<p>Invalid module. Please select another</p>' )
+            modTup = self.modules[ mod[0] ]
+            if modTup:
+               (modName, module) = modTup
+               module( self.mainUrlWriter ).write_BODY( request )  
+            else:
+               request.write( '<p>Invalid module. Please select another</p>' )
     
         request.write( "   </td></tr>" )
         request.write( "  </table>" )
index 68d050b3bbd863a960d2a11d5380b798b9ae6fd7..f13781bf1ab206c22cac1cc6014b52d08da21329 100755 (executable)
@@ -10,24 +10,18 @@ class NodeInfo( GenTabbed ):
         def newUrlWriter( url ):
             return urlWriter( "mod=node%s" % url )
     
-        GenTabbed.__init__( self, newUrlWriter, [ 'General', 'Dmesg' ], [ NodeGenTab, NodeDmesgTab ] )
+        GenTabbed.__init__( self, "Node Details", newUrlWriter, [ 'General', 'Dmesg', ], [ NodeGeneralTab, NodeDmesgTab ] )
 
-class NodeGenTab( PreTab ):
+class NodeGeneralTab( CompositeTab ):
     def __init__( self ):
-       text = sxp2string( server.xend_node() )
-       PreTab.__init__( self, text )            
-    
-class NodeGeneralTab( GeneralTab ):
+       CompositeTab.__init__( self, [ NodeInfoTab, NodeActionTab ] )        
+        
+class NodeInfoTab( GeneralTab ):
                         
     def __init__( self ):
          
-        nodeInfo = server.xend_node()
-        
-        dictNodeInfo = {}
-        
-        for l in nodeInfo:
-            dictNodeInfo[ l[0] ] = l[1]
-            
+        nodeInfo = sxp2hash( server.xend_node() )
+    
         dictTitles = {}
         dictTitles[ 'System' ] = 'system'
         dictTitles[ 'Hostname' ] = 'host' 
@@ -40,11 +34,24 @@ class NodeGeneralTab( GeneralTab ):
         dictTitles[ 'Memory' ] = ( 'memory', memoryFormatter )
         dictTitles[ 'Free Memory' ] = ( 'free_memory', memoryFormatter )
         
-        GeneralTab.__init__( self, title="General Node Info", dict=dictNodeInfo, titles=dictTitles )
+        GeneralTab.__init__( self, dict=nodeInfo, titles=dictTitles )
 
 class NodeDmesgTab( PreTab ):
 
     def __init__( self ):
         dmesg = server.xend_node_dmesg()
         PreTab.__init__( self, dmesg[ 1 ] )
+  
+class NodeActionTab( ActionTab ):
+
+    def __init__( self ):
+        ActionTab.__init__( self, { "shutdown" : ( "Shutdown the Node", "shutdown.png" ),
+               "reboot" : ( "Reboot the Node", "reboot.png" ) } )    
+        
+    def op_shutdown( self, request ):
+       print ">NodeShutDown"
+       #server.xend_node_shutdown()
     
+    def op_reboot( self, request ):
+       print ">NodeReboot"
+        #server.xend_node_reboot()
index 47d3519011e2b32bdeca56e8eaaae95f68a81a84..64503bad29ff6d62180322826787a46095d55a77 100755 (executable)
@@ -17,8 +17,13 @@ def getDomInfoHash( domain ):
         d['start_time'] = float( sxp.child_value( domInfo, 'start_time' ) )
     return d
 
-def sxp2hash( sxp ):
-    pass
+def sxp2hash( s ):
+    sxphash = {}
+        
+    for child in sxp.children( s ):
+        sxphash[ child[0] ] = child[1]
+        
+    return sxphash
     
 def sxp2string( sxp ):
     class tmp:
@@ -58,7 +63,12 @@ def stateFormatter( state ):
     return state
     
 def memoryFormatter( mem ):
-    return "%7dMb" % mem
+    mem = int( mem )
+    if mem >= 1024:
+        mem = float( mem ) / 1024
+        return "%3.2fGb" % mem
+    else:    
+        return "%7dMb" % mem
 
 def cpuFormatter( mhz ):
     if mhz > 1000:
index 2d08f36056808075aa7a4f15060dd7e42f639728..b0a9c8beca8d44c6ceae7af69f48eb4ff6d5258f 100644 (file)
@@ -366,6 +366,14 @@ class Xend:
     def xend_node(self):
         return self.xendGet(self.nodeurl())
         
+    def xend_node_shutdown(self):
+        return self.xendPost(self.nodeurl(),
+                {'op'      : 'shutdown'})
+                
+    def xend_node_restart(self):
+        return self.xendPost(self.nodeurl(),
+                {'op'      : 'reboot'})
+
     def xend_node_dmesg(self):
         return self.xendGet(self.dmesgurl())
 
index 0321a566f3ad419085118382974e582739df547e..db432d18bed1c55d3e27ae0ba2a7ba0ef38f7859 100755 (executable)
@@ -28,12 +28,16 @@ install:
        install -m0644 images/seperator.jpg $(sv_insdir)/images
        install -m0644 images/seperator-left-highlight.jpg $(sv_insdir)/images
        install -m0644 images/seperator-right-highlight.jpg $(sv_insdir)/images
+       
+       install -m0644 images/shutdown.png $(sv_insdir)/images
+       install -m0644 images/reboot.png $(sv_insdir)/images
 
        # make include folder
        mkdir -p $(sv_insdir)/inc
        
        # copy stylesheet
        install -m0644 inc/style.css $(sv_insdir)/inc
+       install -m0644 inc/script.js $(sv_insdir)/inc
 
 clean:
 
diff --git a/tools/sv/images/reboot.png b/tools/sv/images/reboot.png
new file mode 100755 (executable)
index 0000000..358e6de
Binary files /dev/null and b/tools/sv/images/reboot.png differ
diff --git a/tools/sv/images/shutdown.png b/tools/sv/images/shutdown.png
new file mode 100755 (executable)
index 0000000..48a52dc
Binary files /dev/null and b/tools/sv/images/shutdown.png differ
diff --git a/tools/sv/inc/script.js b/tools/sv/inc/script.js
new file mode 100755 (executable)
index 0000000..fca5a97
--- /dev/null
@@ -0,0 +1,15 @@
+function update( objRef, text )
+{
+    if ( document.all || document.getElementById )
+    {
+        obj = ( document.getElementById )? document.getElementById( objRef ) : document.all( objRef );
+
+        obj.innerHTML= text
+    }
+}
+
+function doOp( op )
+{
+    document.forms[0].op.value = op
+    document.forms[0].submit()
+}
index e819f9254e43ec6df264725a15b1dc6385e6f0d3..263ab59b2342951436221ef3a61078b0e362dd83 100644 (file)
@@ -27,4 +27,6 @@ body {
        
        
        }
-       
\ No newline at end of file
+        
+.button (cursor:hand)
+